using Godot;
using System;
using System.Collections.Generic;
using System.Net.NetworkInformation;

namespace TopDownGodot.Src.Multiplayer
{
    public partial class RoomList : Control
    {
        private PackedScene _roomPackedScene = GD.Load<PackedScene>("res://scene/room.tscn");
        private PacketPeerUdp _packetPeerUdp = new();
        private readonly Dictionary<string, Dictionary<string, Variant>> _packetData = [];
        private VBoxContainer _roomListVBoxContainer;
        private readonly Dictionary<string, Node> _roomNodes = [];

        public override void _Ready()
        {
            var error = _packetPeerUdp.Bind(4433);
            _roomListVBoxContainer = GetNode<VBoxContainer>("ScrollContainer/VBoxContainer");
        }

        public override void _Process(double delta)
        {
            ListenPacketUdp();
        }

        public override void _ExitTree()
        {
            _packetPeerUdp.Close();
        }

        private void OnRefreshPressed()
        {
            _packetData.Clear();
            OnPacketDataUpdateTimerTimeout();
        }

        private void OnPacketDataUpdateTimerTimeout()
        {
            int timer = 5;
            List<string> namesToRemove = [];

            // 清理过期房间数据和节点  
            foreach (var key in new List<string>(_packetData.Keys))
            {
                var lastTime = (long)_packetData[key]["last_time"];
                if (Time.GetUnixTimeFromSystem() - lastTime > timer) // Explicitly cast 'lastTime' to 'double'  
                {
                    string roomName = _packetData[key]["data"].As<Godot.Collections.Dictionary>()["name"].AsString();
                    namesToRemove.Add(roomName);
                    _packetData.Remove(key);
                }
            }

            foreach (var roomName in namesToRemove)
            {
                if (_roomNodes.ContainsKey(roomName))
                {
                    _roomListVBoxContainer.RemoveChild(_roomNodes[roomName]);
                    _roomNodes[roomName].QueueFree();
                    _roomNodes.Remove(roomName);
                }
            }

            // 更新或添加房间节点  
            foreach (var key in _packetData.Keys)
            {
                var data = _packetData[key]["data"].As<Godot.Collections.Dictionary>();
                string roomName = data["name"].AsString();
                int playerNumber = (int)data["player_number"];
                string ip = data["IP"].AsString();
                int port = (int)data["port"];

                if (_roomNodes.ContainsKey(roomName))
                {
                    var node = _roomNodes[roomName];
                    node.GetNode<Label>("RoomName").Text = roomName;
                    node.GetNode<Label>("PlayerNumber").Text = $"{playerNumber}/4";
                    node.GetNode<Label>("IP").Text = ip;
                    node.GetNode<Label>("Port").Text = port.ToString();
                }
                else
                {
                    var roomNode = _roomPackedScene.Instantiate();
                    roomNode.GetNode<Label>("RoomName").Text = roomName;
                    roomNode.GetNode<Label>("PlayerNumber").Text = $"{playerNumber}/4";
                    roomNode.GetNode<Label>("IP").Text = ip;
                    roomNode.GetNode<Label>("Port").Text = port.ToString();
                    _roomListVBoxContainer.CallDeferred("add_child", roomNode);
                    _roomNodes[roomName] = roomNode;
                }
            }
        }

        private static bool PingIp(string ip)
        {
            string host = ip;
            Ping ping = new();
            try
            {
                PingReply reply = ping.Send(host, 1000); // 1000毫秒超时
                if (reply.Status == IPStatus.Success)
                {
                    GD.Print($"Ping {host} 成功，耗时：{reply.RoundtripTime}ms");
                    return true;
                }
                else
                {
                    GD.PrintErr($"Ping {host} 失败，状态：{reply.Status}");
                    return false;
                }
            }
            catch (Exception ex)
            {
                GD.PrintErr($"Ping 发生异常：{ex.Message}");
                return false;
            }
        }

        private void ListenPacketUdp()
        {
            while (_packetPeerUdp.GetAvailablePacketCount() > 0)
            {
                var arrayBytes = _packetPeerUdp.GetPacket();
                string jsonStr = arrayBytes.GetStringFromUtf8();
                var jsonObj = Json.ParseString(jsonStr);

                // 解析失败则丢弃包
                if (jsonObj.VariantType == Variant.Type.Nil)
                    continue;

                var packetJson = jsonObj.AsGodotDictionary();
                packetJson["port"] = packetJson["port"].As<int>(); // 确保端口号是整数类型
                packetJson["max_number"] = packetJson["max_number"].As<int>(); // 确保最大人数是整数类型
                packetJson["player_number"] = packetJson["player_number"].As<int>(); // 确保当前人数是整数类型
                
                string[] primaryKey = ["IP", "port"];
                string[] secondaryKey = ["max_number", "password", "player_number"];

                var ip = packetJson["IP"].AsString();
                var port = (int)packetJson["port"];
                var maxNumber = (int)packetJson["max_number"];
                var playerNumber = (int)packetJson["player_number"];

                if (!PingIp(ip))
                    continue;
                if (port <= 0 && port >= 65535)
                    continue;
                if (maxNumber <= 0 && maxNumber >= 4)
                    continue;
                if (playerNumber <= 0 && playerNumber >= 4)
                    continue;

                //唯一键
                var uniqueKey = $"{ip}:{port}";
                _packetData[uniqueKey] = new Dictionary<string, Variant>
                {
                    { "data", packetJson },
                    { "last_time", Time.GetUnixTimeFromSystem() }
                };

                foreach (var outer in _packetData)
                {
                    GD.Print($"key: {outer.Key}");
                    foreach (var inner in outer.Value)
                    {
                        GD.Print($"  inner key: {inner.Key}, inner value: {inner.Value}");
                    }
                }
                GD.Print("-----------------------------------------");
            }
        }
    }
}